using System;
using System.Globalization;
using NUnit.Framework;
using ValidationFramework.Reflection;

namespace ValidationFramework.Tests
{

	public class NumberConversionRuleTest
	{
		const string expectedErrorMessage = "expectedErrorMessage";
		const string expectedRuleSet = "EXPECTEDRULESET";
		private const TypeCode expectedTypeCode = TypeCode.Int32;
		const NumberStyles expectedNumberStyles = NumberStyles.Integer;

		[TestFixture]
		public class Contruction
		{
			[Test]
			public void AllParams()
			{
				var rule = new NumberConversionRule(expectedTypeCode);
				Assert.AreEqual(expectedTypeCode, rule.TypeCode);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException))]
			public void ExceptionStringTypeCode()
			{
				new NumberConversionRule(TypeCode.String);
			}


			[Test]
			[ExpectedException(typeof(ArgumentException))]
			public void ExceptionDateTimeTypeCode()
			{
				new NumberConversionRule(TypeCode.DateTime);
			}


		}

		[TestFixture]
		public class IsEquivalent
		{

			[Test]
			public void TypeCodeCompare()
			{
				var rule1 = new NumberConversionRule(TypeCode.Int32);
				var rule2 = new NumberConversionRule(TypeCode.Int32);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new NumberConversionRule(TypeCode.Int32);
				rule2 = new NumberConversionRule(TypeCode.Decimal);
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}

			[Test]
			public void NumberFormatInfoCompare()
			{
				var rule1 = new NumberConversionRule(TypeCode.Int32);
				var rule2 = new NumberConversionRule(TypeCode.Int32);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new NumberConversionRule(TypeCode.Int32)
				        	{
				        		NumberFormatInfo = NumberFormatInfo.InvariantInfo
				        	};
				rule2 = new NumberConversionRule(TypeCode.Int32)
				        	{
				        		NumberFormatInfo = NumberFormatInfo.CurrentInfo
				        	};
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}

			[Test]
			public void NumberStylesCompare()
			{
				var rule1 = new NumberConversionRule(TypeCode.Int32);
				var rule2 = new NumberConversionRule(TypeCode.Int32);
				Assert.IsTrue(rule1.IsEquivalent(rule2));

				rule1 = new NumberConversionRule(TypeCode.Int32)
				{
					NumberStyles = NumberStyles.Any
				};
				rule2 = new NumberConversionRule(TypeCode.Int32)
				{
					NumberStyles = NumberStyles.Integer
				};
				Assert.IsFalse(rule1.IsEquivalent(rule2));
			}
		}



		[TestFixture]
		public class RuleInterpretation
		{
			[Test]
			public void Simple()
			{
				var nullableRule = new NumberConversionRule(TypeCode.Int32);
				Assert.IsNotNull(nullableRule.RuleInterpretation);

			}
		}

		[TestFixture]
		public class Validate
		{

			[Test]
			public void Simple()
			{
				var rule = new NumberConversionRule(TypeCode.Decimal);

				Assert.IsTrue(rule.Validate(null, null, null, null));
                Assert.IsTrue(rule.Validate(null, string.Empty, null, null));
				Assert.IsFalse(rule.Validate(null, "sdf", null, null));
                Assert.IsTrue(rule.Validate(null, "1.2 2", null, null));
                Assert.IsTrue(rule.Validate(null, "1 2", null, null));

			}

		}

		[TestFixture]
		public class CheckTypes
		{


			[Test]
			public void Simple()
			{
			    var rule = new NumberConversionRule(TypeCode.Int32);
			    rule.CheckType(new MockInfoDescriptor(TypePointers.StringTypeHandle, "foo"));
			}


		    [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a 'System.String' to be used for the ValidationFramework.NumberConversionRule. Actual Type 'System.Int32'.\r\nParameter name: value")]
            public void ExceptionIncorrectType()
            {
		        var rule = new NumberConversionRule(TypeCode.Int32);
		        rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
            }
		}

	}
}